// FileFolderPluginOpen.cpp

#include "StdAfx.h"

#include "../../resource.h"

#include "Common/Agent/Agent.h"

#include "Common/Lang/LangUtils.h"
#include "../../OpenCallback.h"
#include "Common/Plugin/PluginLoader.h"
#include "Common/Registry/RegistryAssociations.h"
#include "Common/Registry/RegistryPlugins.h"

namespace FileManager
{
namespace FileSystem
{


using namespace Common;
using namespace Registry;

struct CThreadArchiveOpen
{
	CString Path;
	CString ArcFormat;
	CComPtr<IInStream> InStream;
	CComPtr<IFolderManager> FolderManager;
	CComPtr<IProgress> OpenCallback;
	COpenArchiveCallback* OpenCallbackSpec;

		CComPtr<IFolderFolder> Folder;
	HRESULT Result;

	System::Threading::CEvent ThreadEvent;

	CThreadArchiveOpen()
	{
		ThreadEvent.Create();
	}

	void Process()
	{
		try
		{
			CProgressCloser closer(OpenCallbackSpec->ProgressDialog);
			Result = FolderManager->OpenFolderFile(InStream, Path, ArcFormat, &Folder, OpenCallback);
		}
		catch(...)
		{
			Result = E_FAIL;
		}
	}

	static void WINAPI MyThreadFunction(void* param)
	{
		((CThreadArchiveOpen*)param)->Process();
	}
};

/*
static int FindPlugin(const std::vector<CPluginInfo> &plugins, const CString &pluginName)
{
  for (int i = 0; i < plugins.size(); i++)
	if (plugins[i].Name.CompareNoCase(pluginName) == 0)
	  return i;
  return -1;
}
*/

HRESULT OpenFileFolderPlugin(IInStream* inStream, const CString &path, const CString &arcFormat,
			HMODULE* module, IFolderFolder** resultFolder, HWND parentWindow,
			bool &encrypted, CString &password, 
			std::shared_ptr<Common::System::Threading::CSimpleWorkerPool>* pool)
{
	ATLASSERT(NULL != pool);

	std::vector<std::shared_ptr<CPluginInfo> > plugins;
	ReadFileFolderPluginInfoList(plugins);

	CString extension, pureName, dot;

	int slashPos = path.ReverseFind(CHAR_PATH_SEPARATOR);
	CString dirPrefix;
	CString fileName;
	if (slashPos >= 0)
	{
		dirPrefix = path.Left(slashPos + 1);
		fileName = path.Mid(slashPos + 1);
	}
	else
	{
		fileName = path;
	}

	Common::FileSystem::FileName::SplitNameToPureNameAndExtension(fileName, pureName, dot, extension);

	/*
	if (!extension.IsEmpty())
	{
	  CExtInfo extInfo;
	  if (ReadInternalAssociation(extension, extInfo))
	  {
		for (int i = extInfo.Plugins.Size() - 1; i >= 0; i--)
		{
		  int pluginIndex = FindPlugin(plugins, extInfo.Plugins[i]);
		  if (pluginIndex >= 0)
		  {
			const CPluginInfo plugin = plugins[pluginIndex];
			plugins.Delete(pluginIndex);
			plugins.Insert(0, plugin);
		  }
		}
	  }
	}
	*/

	HRESULT hRes(S_OK);
	for (size_t i = 0; i < plugins.size(); i++)
	{
		const auto &plugin = plugins[i];
		if (!plugin->ClassIDDefined)
		{
			continue;
		}
		Plugin::CPluginLibrary library;

		CThreadArchiveOpen thArcOpen;

		if (plugin->FilePath.IsEmpty())
		{
			Agent::CArchiveFolderManager* manager = new  CComObject<Agent::CArchiveFolderManager>;
			manager->FinalConstruct();
			thArcOpen.FolderManager = manager;
		}
		else if (library.LoadAndCreateManager(plugin->FilePath, plugin->ClassID, &thArcOpen.FolderManager) != S_OK)
		{
			continue;
		}

		thArcOpen.OpenCallbackSpec = new CComObject<COpenArchiveCallback>;
		thArcOpen.OpenCallbackSpec->FinalConstruct();
		thArcOpen.OpenCallback = thArcOpen.OpenCallbackSpec;
		thArcOpen.OpenCallbackSpec->PasswordIsDefined = encrypted;
		thArcOpen.OpenCallbackSpec->Password = password;
		thArcOpen.OpenCallbackSpec->ParentWindow = parentWindow;

		if (inStream)
		{
			thArcOpen.OpenCallbackSpec->SetSubArchiveName(fileName);
		}
		else
		{
			thArcOpen.OpenCallbackSpec->LoadFileInfo(dirPrefix, fileName);
		}

		thArcOpen.InStream = inStream;
		thArcOpen.Path = path;
		thArcOpen.ArcFormat = arcFormat;

		CString progressTitle = Lang::LangString(IDS_OPENNING, 0x03020283);
		thArcOpen.OpenCallbackSpec->ProgressDialog.MainWindow = parentWindow;
		thArcOpen.OpenCallbackSpec->ProgressDialog.MainTitle = Lang::LangString(IDS_APP_TITLE, 0x03000000);
		thArcOpen.OpenCallbackSpec->ProgressDialog.MainAddTitle = progressTitle + CString(_T(" "));
		thArcOpen.OpenCallbackSpec->ProgressDialog.WaitMode = true;

		{
			(*pool)->AddHighPriorityTask(CThreadArchiveOpen::MyThreadFunction, &thArcOpen, thArcOpen.ThreadEvent);
			thArcOpen.OpenCallbackSpec->StartProgressDialogAndWait(progressTitle, thArcOpen.ThreadEvent);
		}

		if (thArcOpen.Result == E_ABORT)
		{
			return thArcOpen.Result;
		}

		if (thArcOpen.Result == S_OK)
		{
			// if (openCallbackSpec->PasswordWasAsked)
			{
				encrypted = thArcOpen.OpenCallbackSpec->PasswordIsDefined;
				password = thArcOpen.OpenCallbackSpec->Password;
			}
			*module = library.Detach();
			*resultFolder = thArcOpen.Folder.Detach();
			return S_OK;
		}

		if (thArcOpen.Result != S_FALSE)
		{
			return thArcOpen.Result;
		}
	}
	return S_FALSE;
}

} //namespace FileSystem
} //namespace FileManager
